package com.gitee.cloorc.evaluator;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.flink.table.functions.ScalarFunction;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.StringUtils;

import java.io.PrintStream;
import java.util.HashMap;
import java.util.Map;

/**
 * @author z0228
 */
public class SpEL extends ScalarFunction {
	private static final Map<String, Expression> CACHES = new HashMap<>();
	private static final SpelExpressionParser SEP = new SpelExpressionParser();
	private static final PrintStream PS = System.out;
	private static final ObjectMapper OM = new ObjectMapper();

	public static class Args {
		@SuppressWarnings("WeakerAccess")
		public final Object[] args;

		Args(Object[] args) {
			this.args = args;
		}
	}

	public String eval(Object field, String action) {
		switch (action) {
			case "type":
				return field == null ? "NULL" : field.getClass().getName();
			case "json":
				try {
					return OM.writeValueAsString(field);
				} catch (JsonProcessingException e) {
					return e.getMessage();
				}
			default:
				break;
		}
		return field.toString();
	}

	public long eval(String expression, Object... fields) {
		final long startAt = System.currentTimeMillis();
		try {
			if (!StringUtils.hasText(expression)) {
				return 0;
			}
			final Expression exp = CACHES.computeIfAbsent(expression, SEP::parseExpression);
			final Object value = exp.getValue(new StandardEvaluationContext(new Args(fields)));
			if (value instanceof Number) {
				return ((Number) value).longValue();
			}
			if (value instanceof Boolean) {
				return (Boolean) value ? 1 : 0;
			}
			return Long.MIN_VALUE;
		} finally {
			PS.println("SpEL evaluated in " + (System.currentTimeMillis() - startAt)
				+ "ms : " + expression);
		}
	}
}
